package org.mame.util;

import java.io.File;
import java.io.FileWriter;
import java.io.IOException;

import javax.swing.JFrame;
import javax.swing.JOptionPane;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.dom.DOMDocumentFactory;
import org.dom4j.io.OutputFormat;
import org.dom4j.io.SAXReader;
import org.dom4j.io.XMLWriter;

/**
 * XMLProcessor is a utility class to reaqd and write XML files 
 * using the DOM4j package and SAX processor
 * 
 * @author Bill
 * @version 1.1.0
 *
 */
public class XMLProcessor {
	private static Logger log = LogManager.getLogger(XMLProcessor.class.getName());
	
	// Constants
	private static final String XML_INDENT_SPACING = "\t";
	
	// Global Constants
	@SuppressWarnings("unused")
	private static final String XML_VERSION = "1.0"; // unused until DOM4j supports the functionality behind setting it
	
	/**
	 * Creates a new, blank DOM document
	 * 
	 * @return org.dom4j.Document- The blank DOM Document object
	 */
	public static Document createNewDomDoc(){
		return  DOMDocumentFactory.getInstance().createDocument();
	}
	
	/**
	 * Creates an XML Document from the xml file pointed to by <path>
	 * 
	 * @param path- The absolute file path to the xml file
	 * 
	 * @return org.dom4j.Document- The XML file represented in a DOM object
	 */
	public static Document importDoc(String path){
		log.debug("Attempting to load file denoted by path " + path);
		
		// Path is checked in the called method, no need here it would be redundant
		Document doc = importDoc(new File(path));
		
		// Initialize the new document.  May be utilized more fully at a later time
		//doc.setXmlVersion(XML_VERSION);
		
		return doc;
	}
	
	/**
	 * Creates an XML Document form the xml file pointed to by <file>
	 * 
	 * @param file- A java.io.File pointing to the xml document to load
	 * 
	 * @return org.dom4j.Document- The XML file represented in a DOM object
	 */
	public static Document importDoc(File file){
		log.debug("Attempting to load file " + file.getAbsolutePath());
		
		// See if the file even exists
		if(!file.exists()){
			log.warn("Location " + file.getAbsolutePath() + " does not exist, check for create new file");
			int overwrite = JOptionPane.showConfirmDialog(new JFrame(), file.getAbsolutePath() + " does not exist.  Create it?", "", JOptionPane.OK_CANCEL_OPTION, JOptionPane.WARNING_MESSAGE);
			if(overwrite == JOptionPane.OK_OPTION){
				log.info("Creating new document " + file.getAbsolutePath());
				return createNewDomDoc();
			}else{
				log.error("File " + file.getAbsolutePath() + " does not exist and we were told not to create it.  Good bye!");
				return null;
			}
		// Now check to see if the file is a file or a directory
		}else if (!file.isFile()){
			log.error("Location " + file.getAbsolutePath() + " exists but is not a file." +
					" Perhaps it is a directory?");
			return null;
		}else{
			// Get the file's extension, make sure it is an xml file
			String extension = file.getAbsolutePath().substring(file.getAbsolutePath().lastIndexOf("."));
			if(!".xml".equalsIgnoreCase(extension)){
				log.error("File " + file.getAbsolutePath() + " must be an XML file to be loaded. " +
						"It is currently of type " + extension);
				return null;
			}
		}
		
		// Passes all pre-read testing, attempt to load the file into a Document
		SAXReader reader = new SAXReader();
		Document doc = null;
		
		try {
			doc = reader.read(file);
		} catch (DocumentException e) {
			// TODO Auto-generated catch block
			log.error("Error reading document located at " + file.getAbsolutePath());
			e.printStackTrace();
			return null;
		}
		
		return doc;
	}
	
	/**
	 * Takes the DOM Document and writes it to the file system at the location denoted by <path>
	 * 
	 * @param path- The absolute file path denoting where to place the XML file
	 * @param doc- The DOM Document to write into the XML file
	 */
	public static void writeDoc(String path, Document doc){
		log.debug("Passing work off to writeDoc(File, Document)");
		writeDoc(new File(path), doc);
	}
	
	/**
	 * Takes the DOM Document and writes it to the file system at the location referenced by <file>
	 * 
	 * @param file- the File pointing to the location to save the XML document
	 * @param doc- The DOM Document to write into the XML file
	 */
	public static void writeDoc(File file, Document doc){
		log.debug("Attempting to write file " + file.getAbsolutePath());
		
		XMLWriter writer;
		OutputFormat format;
		
		try{
			if(file.exists()){
				// Overwrite dialogue			
			}else{
				file.createNewFile();
			}
			
			// Set up the formatter for purdied-up words
			format = OutputFormat.createPrettyPrint();
			format.setExpandEmptyElements(true);
			format.setIndent(XML_INDENT_SPACING);
			format.setXHTML(true);
			
			// Create a writer and send the file to it
			writer = new XMLWriter(new FileWriter(file), format);
			writer.write(doc);
			writer.close(); // Probably should be in a finally block, but don't feel like setting up the exception on the calling side
		}catch(IOException ioe){
			log.error("Error writing to output file, see log for details");
			ioe.printStackTrace();
		}
	}
}
